//------------------------------------------------------------------------------
// XMLDocument.h
//------------------------------------------------------------------------------
// File provided for Microsoft Shared Source.
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF 
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO 
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 
// PARTICULAR PURPOSE.
//------------------------------------------------------------------------------
//
// Helper classes for the XML DOM
//
//------------------------------------------------------------------------------

#pragma once

#include <msxml2.h>

////////////////////////////////////////////////////////////////////////////////

class CXMLNode
{
public:
    HRESULT Attach(__in IXMLDOMNode *pxmlNode);
    HRESULT GetXML(__deref_out BSTR *pbstrXML) const;
    HRESULT SelectNode(PCWSTR pszPattern, __deref_out IXMLDOMNode **ppxmlNode) const;
    HRESULT TestPattern(PCWSTR pszPattern) const;
    HRESULT EnumerateNodes(PCWSTR pszPattern, __deref_out IXMLDOMNodeList **ppxmlNodeList) const;
    HRESULT AddNode(PCWSTR pszPattern, PCWSTR pszNodeName, PCWSTR pszNodeText);
    HRESULT RemoveNode(PCWSTR pszPattern, PCWSTR pszNodeName);

    HRESULT GetNodeValue(PCWSTR pszPattern, __inout CComVariant &svarVal) const;
    HRESULT GetNodeValue(PCWSTR pszPattern, __out long *plVal) const;
    HRESULT GetNodeValue(PCWSTR pszPattern, __out DWORD *pdwVal) const;
    HRESULT GetNodeValue(PCWSTR pszPattern, __out_ecount(cch) PWSTR pszVal, DWORD cch) const;
    HRESULT GetNodeValue(PCWSTR pszPattern, __out UINT *puiVal) const;
    HRESULT GetNodeValue(PCWSTR pszPattern, __out float *pflVal) const;
    HRESULT GetNodeValue(PCWSTR pszPattern, __out double *pdblVal) const;
    HRESULT SetNodeText(PCWSTR pszPattern, PCWSTR pszText);

    HRESULT GetAttribute(PCWSTR pszPattern, PCWSTR pszName, __inout CComVariant &svarVal) const;
    HRESULT GetAttribute(PCWSTR pszPattern, PCWSTR pszName, __out float *pflVal) const;
    HRESULT GetAttribute(PCWSTR pszName, __inout CComVariant &svarVal) const;
    HRESULT GetAttribute(PCWSTR pszName, __out_ecount(cch) PWSTR pszVal, DWORD cch) const;
    HRESULT GetAttribute(PCWSTR pszName, __out int *piVal) const;
    HRESULT GetAttribute(PCWSTR pszName, __out long *plVal) const;
    HRESULT GetAttribute(PCWSTR pszName, __out UINT *puiVal) const;
    HRESULT GetAttribute(PCWSTR pszName, __out DWORD *pdwVal) const;
    HRESULT SetAttribute(PCWSTR pszName, __in CComVariant &svarVal);
    HRESULT SetAttribute(PCWSTR pszName, PCWSTR pszVal);
    HRESULT SetAttribute(PCWSTR pszName, int iVal);
    HRESULT SetAttribute(PCWSTR pszName, long lVal);
    HRESULT SetAttribute(PCWSTR pszName, UINT uiVal);

    operator IXMLDOMNode*();
    IXMLDOMNode **operator&();
    IXMLDOMNode *operator=(__in_opt IXMLDOMNode *pxmlNode);
    IXMLDOMNode *operator->() const;

private:
    HRESULT _GetTypedAttribute(PCWSTR pszPattern, PCWSTR pszName, VARTYPE vt, __inout CComVariant &svarValue) const;
    HRESULT _GetTypedAttribute(PCWSTR pszName, VARTYPE vt, __inout CComVariant &svarValue) const;

protected:
    CComPtr<IXMLDOMNode> _spxmlNode;
};

inline HRESULT CXMLNode::Attach(__in IXMLDOMNode *pxmlNode)
{
    HRESULT hr = E_FAIL;
    if (pxmlNode)
    {
        hr = S_OK;
        _spxmlNode = pxmlNode;
    }
    return hr;
}

inline HRESULT CXMLNode::GetXML(__deref_out BSTR *pbstrXML) const
{
    HRESULT hr = E_FAIL;
    if (_spxmlNode)
    {
        hr = _spxmlNode->get_xml(pbstrXML);
    }
    return hr;
}

inline HRESULT CXMLNode::SetAttribute(PCWSTR pszName, PCWSTR pszVal)
{
    CComVariant svar = pszVal;
    return SetAttribute(pszName, svar);
}

inline HRESULT CXMLNode::SetAttribute(PCWSTR pszName, int iVal)
{
    CComVariant svar = iVal;
    return SetAttribute(pszName, svar);
}

inline HRESULT CXMLNode::SetAttribute(PCWSTR pszName, long lVal)
{
    CComVariant svar = lVal;
    return SetAttribute(pszName, svar);
}

inline HRESULT CXMLNode::SetAttribute(PCWSTR pszName, UINT uiVal)
{
    CComVariant svar = uiVal;
    return SetAttribute(pszName, svar);
}

inline CXMLNode::operator IXMLDOMNode*()
{
    return _spxmlNode;
}

inline IXMLDOMNode **CXMLNode::operator&()
{
    return &_spxmlNode;
}

inline IXMLDOMNode *CXMLNode::operator=(__in_opt IXMLDOMNode *pxmlNode)
{
    _spxmlNode = pxmlNode;
    return *this;
}

inline IXMLDOMNode *CXMLNode::operator->() const
{
    return _spxmlNode;
}

////////////////////////////////////////////////////////////////////////////////

class CXMLDocument : public CXMLNode
{
public:
    // Operations
    HRESULT Load(__in HINSTANCE hinst, UINT uiResID);
    HRESULT Load(__in CComVariant &varSource, BOOL fSynchronous = TRUE);
    HRESULT Load(PCWSTR pszSource, BOOL fSynchronous = TRUE);
    HRESULT Load(PCWSTR pszSource, PCWSTR pszPostData, BOOL fSynchronous = TRUE);
    HRESULT LoadXML(PCWSTR pszSource);
    HRESULT Save(PCWSTR pszPath);
    HRESULT SetSelectionLanguage(PCWSTR pszLanguage);
    HRESULT Validate(const CXMLDocument &xmlSchema) const;
    HRESULT Clone(__inout CXMLDocument &xmlDocClone) const;
    HRESULT Insert(__in CXMLDocument &xmlDocSrc, PCWSTR pszPatternRoot, PCWSTR pszPatternSrc, PCWSTR pszPatternDst);
    HRESULT Transform(__in CXMLDocument &xmlXSL, __deref_out BSTR *pbstrTransform) const;
    HRESULT Transform(__in CXMLDocument &xmlXSL, __inout CXMLDocument &xmlDocDst) const;

    operator IXMLDOMDocument2*();

private:
    HRESULT _EnsureXmlDocument();
    HRESULT _EnsureRootNode();

private:
    CComPtr<IXMLDOMDocument2> _spxmlDoc;
};

inline HRESULT CXMLDocument::Load(PCWSTR pszSource, BOOL fSynchronous)
{
    CComVariant svarSource;
    svarSource = pszSource;
    return Load(svarSource, fSynchronous);
}

inline HRESULT CXMLDocument::Save(PCWSTR pszPath)
{
    HRESULT hr = E_FAIL;
    if (_spxmlDoc)
    {
        CComVariant svarDestination;
        svarDestination = pszPath;
        hr = _spxmlDoc->save(svarDestination);
    }
    return hr;
}

inline HRESULT CXMLDocument::SetSelectionLanguage(PCWSTR pszLanguage)
{
    HRESULT hr = E_FAIL;
    if (_spxmlDoc)
    {
        try
        {
            hr = _spxmlDoc->setProperty(L"SelectionLanguage", CComVariant(pszLanguage));
        }
        catch (CAtlException &e)
        {
            hr = e.m_hr;
        }
    }
    return hr;
}

inline CXMLDocument::operator IXMLDOMDocument2*()
{
    return _spxmlDoc;
}

////////////////////////////////////////////////////////////////////////////////

class CXMLNodeList
{
public:
    HRESULT GetNodeCount(__out long *pcNodes) const;
    HRESULT NextNode(__deref_out IXMLDOMNode **ppxmlNode);
    HRESULT NextNode(__inout CXMLNode &xmlNode);
    HRESULT Reset();

    operator IXMLDOMNodeList*();
    IXMLDOMNodeList** operator&();

private:
    CComPtr<IXMLDOMNodeList> _spxmlNodeList;
};

inline HRESULT CXMLNodeList::NextNode(__deref_out IXMLDOMNode **ppxmlNode)
{
    HRESULT hr = E_FAIL;
    if (_spxmlNodeList)
    {
        hr = _spxmlNodeList->nextNode(ppxmlNode);
    }
    return hr;
}

inline HRESULT CXMLNodeList::NextNode(__inout CXMLNode &xmlNode)
{
    CComPtr<IXMLDOMNode> spxmlNode;
    HRESULT hr = NextNode(&spxmlNode);
    if (SUCCEEDED(hr))
    {
        hr = xmlNode.Attach(spxmlNode);
    }
    return hr;
}

inline HRESULT CXMLNodeList::Reset()
{
    HRESULT hr = E_FAIL;
    if (_spxmlNodeList)
    {
        hr = _spxmlNodeList->reset();
    }
    return hr;
}

inline CXMLNodeList::operator IXMLDOMNodeList*()
{
    return _spxmlNodeList;
}

inline IXMLDOMNodeList **CXMLNodeList::operator&()
{
    ATLASSERT(_spxmlNodeList == NULL);
    return &_spxmlNodeList;
}
